#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

#define SOCKET_PATH "/tmp/unix_socket_example" // 套接字文件路径

int recv_fd(int socket)
{
    struct msghdr msg = {0};
    char buf[256];
    struct iovec io = {.iov_base = buf, .iov_len = sizeof(buf)};
    msg.msg_iov = &io;
    msg.msg_iovlen = 1;

    char ctrl_buf[CMSG_SPACE(sizeof(int))];
    msg.msg_control = ctrl_buf;
    msg.msg_controllen = sizeof(ctrl_buf);

    if (recvmsg(socket, &msg, 0) < 0)
    {
        perror("recvmsg failed");
    }
    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
    if (cmsg == NULL)
    {
        fprintf(stderr, "No ancillary data received\n");
    }
    else if (cmsg->cmsg_level != SOL_SOCKET)
    {
        fprintf(stderr, "Invalid cmsg_level: %d\n", cmsg->cmsg_level);
    }
    else if (cmsg->cmsg_type != SCM_RIGHTS)
    {
        fprintf(stderr, "Expected SCM_RIGHTS, got %d\n", cmsg->cmsg_type);
    }
    if (cmsg && cmsg->cmsg_type == SCM_RIGHTS)
    {
        return *(int *)CMSG_DATA(cmsg); // 提取FD
    }
    return -1;
}

int main()
{
    int server_fd, client_fd;
    struct sockaddr_un server_addr, client_addr;
    socklen_t client_addr_len = sizeof(client_addr);
    char buffer[256];

    // 1. 创建UNIX域套接字
    server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (server_fd == -1)
    {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    // 2. 绑定套接字到文件路径
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sun_family = AF_UNIX;
    strncpy(server_addr.sun_path, SOCKET_PATH, sizeof(server_addr.sun_path) - 1);

    unlink(SOCKET_PATH); // 删除已有文件（防止冲突）
    if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
    {
        perror("bind");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    // 3. 监听连接
    if (listen(server_fd, 5) == -1)
    {
        perror("listen");
        close(server_fd);
        exit(EXIT_FAILURE);
    }
    printf("Server listening on %s\n", SOCKET_PATH);

    // 4. 接受客户端连接
    client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_addr_len);
    if (client_fd == -1)
    {
        perror("accept");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    // 5. 接收数据
    int recv = recv_fd(client_fd); // 接收FD
    printf("reve_fd:%d", recv);
    char data[256];
    read(recv, data, sizeof(data)); // 直接操作传递的文件
    printf("Read: %s\n", data);
    // 6. 清理资源
    close(client_fd);
    close(server_fd);
    unlink(SOCKET_PATH); // 删除套接字文件
    return 0;
}
